ORG 0000H
	SJMP 0030H
ORG 000BH
    LJMP TIM0_INTERRUPT
ORG 001BH
    ; LJMP TIM1_INTERRUPT
ORG 0023H
    LJMP UART_INTERRUPT
ORG 0030H
    LJMP MAIN

; ---------------RAM---------------
; RAM 位地址可用范围为 00H~7FH (20~2FH)
; RAM 字节地址可用范围为 30H~7FH

; @brief LED显示缓存 
;       占用 DATA 20H, 30H~37H, BIT 00H~07H
LED_DATA:
    LED_SHOW_BUF_BLINKs DATA 20H
    LED_SHOW_BUF_BLINK0 BIT 00H
    LED_SHOW_BUF_BLINK1 BIT 01H
    LED_SHOW_BUF_BLINK2 BIT 02H
    LED_SHOW_BUF_BLINK3 BIT 03H
    LED_SHOW_BUF_BLINK4 BIT 04H
    LED_SHOW_BUF_BLINK5 BIT 05H
    LED_SHOW_BUF_BLINK6 BIT 06H
    LED_SHOW_BUF_BLINK7 BIT 07H
    LED_SHOW_BUF0       DATA 30H
    LED_SHOW_BUF1       DATA 31H
    LED_SHOW_BUF2       DATA 32H
    LED_SHOW_BUF3       DATA 33H
    LED_SHOW_BUF4       DATA 34H
    LED_SHOW_BUF5       DATA 35H
    LED_SHOW_BUF6       DATA 36H
    LED_SHOW_BUF7       DATA 37H

; @brief 定时器计时缓存 
;       占用 DATA 21H, 38H~3FH, BIT 08H~0FH
TIM0_DATA:
    TIM0_5ms            DATA 38H
    TIM0_SECOND         DATA 39H
    TIM0_MINUTE         DATA 3AH
    TIM0_HOUR           DATA 3BH
    TIM0_DATE           DATA 3CH
    TIM0_MONTH          DATA 3DH
    TIM0_YEAR           DATA 3EH
    TIM0_DATE_OVERFLOW  DATA 3FH
    TIM0_CHOOSE_FLAGs   DATA 21H
    TIM0_SECOND_CHOOSE  BIT 08H
    TIM0_MINUTE_CHOOSE  BIT 09H
    TIM0_HOUR_CHOOSE    BIT 0AH
    TIM0_DATE_CHOOSE    BIT 0BH
    TIM0_MONTH_CHOOSE   BIT 0CH
    TIM0_YEAR_CHOOSE    BIT 0DH

; @brief 秒表计时储存
STOPWATCH_DATA:
    STOPWATCH_SECOND    DATA 40H
    STOPWATCH_MINUTE    DATA 41H
    STOPWATCH_HOUR      DATA 42H
    STOPWATCH_ON_5ms    DATA 43H
    STOPWATCH_RUNNING   BIT 10H
    STOPWATCH_UPDATED   BIT 11H

; @brief 闹钟时间储存
ALARM_SECOND    DATA 48H
ALARM_MINUTE    DATA 49H
ALARM_HOUR      DATA 4AH

; @brief 按键状态存储
;       占用 DATA 23H~24H, 50H~54H， BIT 18H~27H
KEY_DATA:
    KEY_SCAN_TIME   DATA 50H
    KEY_TIME        DATA 51H
    P1N_0           DATA 52H
    P1N_1           DATA 53H
    P1N_2           DATA 54H
    KEY             DATA 23H
    KEY3            BIT 18H
    KEY2            BIT 19H
    KEY1            BIT 1AH
    KEY0            BIT 1BH
    KEY_LONG        DATA 24H
    KEY_LONG3       BIT 20H
    KEY_LONG2       BIT 21H
    KEY_LONG1       BIT 22H
    KEY_LONG0       BIT 23H

UART_DATA:
    UART_BEG_PTR    DATA 55H
    UART_END_PTR    DATA 56H
    UART_DATA_SIZE  DATA 57H
    UART_DATA0      DATA 58H
    UART_DATA1      DATA 59H
    UART_DATA2      DATA 5AH
    UART_DATA3      DATA 5BH
    UART_DATA4      DATA 5CH
    UART_DATA5      DATA 5DH
    UART_DATA6      DATA 5EH
    UART_DATA7      DATA 5FH
    UART_DATA8      DATA 60H
    UART_DATA9      DATA 61H
    UART_DATA10     DATA 62H
    UART_DATA11     DATA 63H
    UART_DATA12     DATA 64H
    UART_DATA13     DATA 65H
    UART_DATA14     DATA 66H
    UART_DATA15     DATA 67H

; @brief 时钟运行状态标志位
;       占用 DATA 2EH~2FH, BIT 70H~7FH
SHOW_TIME_FLAG      BIT 70H
SHOW_DATE_FLAG      BIT 71H 
TIME_CHANGE_FLAG    BIT 72H
SHOW_STOPWATCH_FLAG BIT 73H
SHOW_ALARM_FLAG     BIT 74H
ALARM_BEEP_FLAG     BIT 75H

; ---------------RAM---------------

; ---------------LED---------------

; @brief: LED数字表
LED_TABLE:
    LED_SHOW_0: DB 00111111B ; 0
    LED_SHOW_1: DB 00000110B ; 1
    LED_SHOW_2: DB 01011011B ; 2
    LED_SHOW_3: DB 01001111B ; 3
    LED_SHOW_4: DB 01100110B ; 4
    LED_SHOW_5: DB 01101101B ; 5
    LED_SHOW_6: DB 01111101B ; 6
    LED_SHOW_7: DB 00000111B ; 7
    LED_SHOW_8: DB 01111111B ; 8
    LED_SHOW_9: DB 01101111B ; 9
    LED_SHOW_L: DB 01000000B ; -
    LED_SHOW_P: DB 10000000B ; .

; @brief: LED初始化
LED_INIT:
    SETB RS1
    MOV R0, #LED_SHOW_BUF0
    MOV R3, #8
    LED_INIT_LOOP:
        MOV @R0, #00111111B
        INC R0
        DJNZ R3, LED_INIT_LOOP
    CLR RS1
    RET

; @brief: 令被选中 LED 灯显示数字 A
; @param: A 显示的数字 0 ~ 9 , 10为横线
LED_SHOW_NUM:
    PUSH ACC
    MOV DPTR, #LED_TABLE
    MOVC A, @A+DPTR
    MOV P0, A
    POP ACC
    RET

; @brief: 令被选中第 A 个 LED 灯
; @param: A 选中的 LED 灯 0 ~ 7
LED_CHOOSE:
    PUSH ACC
    RL A
    RL A        ; A << 2
    ANL P2, A   ; P2 = P2 & A
    ORL P2, A   ; P2 = P2 | A
    POP ACC
    RET

; @brief 显示LED显示缓存中的数据
LED_SHOW_BUF:
    SETB RS1
    PUSH ACC
    PUSH B
    MOV A, LED_SHOW_BUF_BLINKs
    JZ LED_SHOW_BUF_BLINK_END
        MOV A, TIM0_5ms
        MOV B, #100
        DIV AB
        JZ LED_SHOW_BUF_BLINK_END
            MOV R7, #8H
            MOV R6, LED_SHOW_BUF_BLINKs
            MOV R0, #LED_SHOW_BUF0
            LED_SHOW_BUF_BLINK_LOOP:
                MOV A, R6
                ANL A, #00000001B
                JZ LED_SHOW_BUF_BLINK_LOOP_END
                    MOV A, @R0
                    ANL A, #10000000B
                    MOV @R0, A
                LED_SHOW_BUF_BLINK_LOOP_END:
                MOV A, R6
                RR A
                MOV R6, A
                INC R0
                DJNZ R7, LED_SHOW_BUF_BLINK_LOOP
    LED_SHOW_BUF_BLINK_END:
    MOV R7, #8H
    LOOP_LED_SHOW_BUF:
        MOV A, R7
        DEC A
        LCALL LED_CHOOSE
        ADD A, #LED_SHOW_BUF0
        MOV R0, A
        MOV P0, @R0
        MOV R6, #16
        LED_SHOW_BUF_WAIT:
            NOP
            DJNZ R6, LED_SHOW_BUF_WAIT
        LED_SHOW_BUF_WAIT_END:
        MOV P0, #0
        DJNZ R7, LOOP_LED_SHOW_BUF
    CLR RS1
    POP B
    POP ACC
    RET

; @brief LED 显示10进制数字 A
; @param: A 显示的数字 0~FFH (0~255)
LED_BUF_A:
    PUSH ACC
    PUSH B
    SETB RS1
    MOV DPTR, #LED_TABLE
    MOV R0, #LED_SHOW_BUF0
    MOV R7, A
    LED_BUF_A_LOOP:
        MOV A, R7
        MOV B, #10
        DIV AB
        MOV R7, A
        MOV A, B
        MOVC A, @A+DPTR
        MOV @R0, A
        INC R0
        CJNE R7, #0, LED_BUF_A_LOOP
    CLR RS1
    POP B
    POP ACC
    RET


; ---------------LED---------------

; ---------------TIM0---------------

TIM0_BIG_MONTH_TABLE:
    DB 1,0,1,0,1,0,1,1,0,1,0,1

; @brief TIM0定时器0 初始化 模式0周期5ms 开启中断
TIM0_INIT:
    ; 延时 5ms, 11.0592 MHz 计数一次 625/576 us 预设值为 8192 - 5000/(625/576) = 8192 - 4608 = 3584
    ; TL = 00000B = 00H
    ; TH = 01110000B = 70H
    ; 延时 5ms, 12 MHz 计数一次 1 us 预设值为 8192 - 5000 = 8192 - 5000 = 3192
    ; TL = 00000B = 18H
    ; TH = 01110000B = 63H
    ANL TMOD, #11111100B
    MOV TL0, #00H
    MOV TH0, #70H
    SETB EA
    SETB ET0
    SETB TR0
    RET

; @brief TIM0定时器0 中断函数 每5ms计数变量自增
TIM0_INTERRUPT:
    MOV TL0, #00H
    MOV TH0, #70H
    INC TIM0_5ms
    RETI

; @brief 初始化计数时间
TIM0_DATE_INIT:
    MOV TIM0_MINUTE, #30
    MOV TIM0_HOUR, #15
    MOV TIM0_SECOND, #00
    MOV TIM0_DATE, #9
    MOV TIM0_MONTH, #7
    MOV TIM0_YEAR, #23
    RET

; @brief TIM0 5ms时间溢出检测 将5ms的时间更新给 秒分时日月年
TIM0_UPDATE_TIME:
    PUSH ACC
    SETB RS1
    MOV R0, #TIM0_5ms
    MOV A, @R0
    SUBB A, #200
    JC TIM0_UPDATE_TIME_END ; if(TIM0_5ms == 200) 1s
        MOV @R0, A ; TIM0_COUNTER[1] = 0
        JB TIME_CHANGE_FLAG, TIM0_UPDATE_TIME_END
        INC R0 ; TIM0_SECOND
        INC @R0 ; TIM0_SECOND++
        CJNE @R0, #60, TIM0_UPDATE_TIME_END ; if(TIM0_SECOND == 60) 1min
            MOV @R0, #0 ; TIM0_SECOND = 0
            INC R0 ; TIM0_MINUTE
            INC @R0 ; TIM0_MINUTE++
            CJNE @R0, #60, TIM0_UPDATE_TIME_END ; if(TIM0_MINUTE == 60) 1hour
                MOV @R0, #0 ; TIM0_MINUTE = 0
                INC R0 ; TIM0_HOUR
                INC @R0 ; TIM0_HOUR++
                CJNE @R0, #24, TIM0_UPDATE_TIME_END ; if(TIM0_HOUR == 24) 1day
                    MOV @R0, #0 ; TIM0_HOUR = 0
                    INC R0 ; TIM0_DATE
                    INC @R0 ; TIM0_DATE++
                    LCALL TIM0_DATE_TEST
                    MOV A, TIM0_DATE_OVERFLOW
                    CLR C
                    SUBB A, @R0
                    JNZ TIM0_UPDATE_TIME_END ; if(TIM0_DATE == OVERFLOW) 1day
                        MOV @R0, #1 ; TIM0_DATE = 1
                        INC R0 ; TIM0_MONTH
                        INC @R0 ; TIM0_MONTH++
                        CJNE @R0, #13, TIM0_UPDATE_TIME_END ; if(TIM0_MONTH == 13) 1day
                            MOV @R0, #1 ; TIM0_HOUR = 0
                            INC R0 ; TIM0_YEAR
                            INC @R0 ; TIM0_YEAR++
    TIM0_UPDATE_TIME_END:
    CLR RS1
    POP ACC
    RET

; @brief 对当前年月进行 闰年 大小月 检测
; @return TIM0_DATE_OVERFLOW 溢出天数
TIM0_DATE_TEST:
    PUSH ACC
    PUSH B
    MOV A, TIM0_MONTH
    CLR C
    SUBB A, #1
    MOV DPTR, #TIM0_BIG_MONTH_TABLE
    MOVC A, @A+DPTR
    JZ TIM0_DATE_TEST_BIG_END
        MOV TIM0_DATE_OVERFLOW, #32
        SJMP TIM0_DATE_TEST_END
    TIM0_DATE_TEST_BIG_END:
        CLR C
        MOV A, TIM0_MONTH
        SUBB A, #2
        JZ TIM0_DATE_TEST_SMALL_END
            MOV TIM0_DATE_OVERFLOW, #31
            SJMP TIM0_DATE_TEST_END
    TIM0_DATE_TEST_SMALL_END:
        MOV A, TIM0_YEAR
        MOV B, #4
        DIV AB
        MOV A, B
        JNZ TIM0_DATE_TEST_LEAP2_END
            MOV TIM0_DATE_OVERFLOW, #30
            SJMP TIM0_DATE_TEST_END
        TIM0_DATE_TEST_LEAP2_END:
            MOV TIM0_DATE_OVERFLOW, #29
    TIM0_DATE_TEST_END:
    POP B
    POP ACC
    RET

; @brief 带检测自增选中数字
TIM0_INC_CHOOSE:
    PUSH ACC
    JNB TIM0_SECOND_CHOOSE, TIM0_SECOND_INC_END
        INC TIM0_SECOND
        MOV A, TIM0_SECOND
        CLR C
        SUBB A, #60
        JNZ TIM0_YEAR_INC_END
            MOV TIM0_SECOND, #0
            LJMP TIM0_YEAR_INC_END
    TIM0_SECOND_INC_END:
    JNB TIM0_MINUTE_CHOOSE, TIM0_MINUTE_INC_END
        INC TIM0_MINUTE
        MOV A, TIM0_MINUTE
        CLR C
        SUBB A, #60
        JNZ TIM0_YEAR_INC_END
            MOV TIM0_MINUTE, #0
            LJMP TIM0_YEAR_INC_END
    TIM0_MINUTE_INC_END:
    JNB TIM0_HOUR_CHOOSE, TIM0_HOUR_INC_END
        INC TIM0_HOUR
        MOV A, TIM0_HOUR
        CLR C
        SUBB A, #24
        JNZ TIM0_YEAR_INC_END
            MOV TIM0_HOUR, #0
            LJMP TIM0_YEAR_INC_END
    TIM0_HOUR_INC_END:
    JNB TIM0_DATE_CHOOSE, TIM0_DATE_INC_END
        LCALL TIM0_DATE_TEST
        INC TIM0_DATE
        MOV A, TIM0_DATE
        CLR C
        SUBB A, TIM0_DATE_OVERFLOW
        JNZ TIM0_YEAR_INC_END
            MOV TIM0_DATE, #1
            LJMP TIM0_YEAR_INC_END
    TIM0_DATE_INC_END:
    JNB TIM0_MONTH_CHOOSE, TIM0_MONTH_INC_END
        INC TIM0_MONTH
        MOV A, TIM0_MONTH
        CLR C
        SUBB A, #13
        JNZ MONTH_INC_END
            MOV TIM0_MONTH, #1
        MONTH_INC_END:
        LCALL TIM0_DATE_TEST
        MOV A, TIM0_DATE
        CLR C
        SUBB A, TIM0_DATE_OVERFLOW
        JC TIM0_YEAR_INC_END
            MOV A, TIM0_DATE_OVERFLOW
            CLR C
            SUBB A, #1
            MOV TIM0_DATE, A
            LJMP TIM0_YEAR_INC_END
    TIM0_MONTH_INC_END:
    JNB TIM0_YEAR_CHOOSE, TIM0_YEAR_INC_END
        INC TIM0_YEAR
        LCALL TIM0_DATE_TEST
        MOV A, TIM0_DATE
        CLR C
        SUBB A, TIM0_DATE_OVERFLOW
        JC TIM0_YEAR_INC_END
            MOV A, TIM0_DATE_OVERFLOW
            CLR C
            SUBB A, #1
            MOV TIM0_DATE, A
            LJMP TIM0_YEAR_INC_END
    TIM0_YEAR_INC_END:
    POP ACC
    RET

; @brief 带检测自减选中数字
TIM0_DEC_CHOOSE:
    PUSH ACC
    JNB TIM0_SECOND_CHOOSE, TIM0_SECOND_DEC_END
        DEC TIM0_SECOND
        MOV A, TIM0_SECOND
        CLR C
        SUBB A, #-1
        JNZ TIM0_YEAR_DEC_END
            MOV TIM0_SECOND, #59
            LJMP TIM0_YEAR_DEC_END
    TIM0_SECOND_DEC_END:
    JNB TIM0_MINUTE_CHOOSE, TIM0_MINUTE_DEC_END
        DEC TIM0_MINUTE
        MOV A, TIM0_MINUTE
        CLR C
        SUBB A, #-1
        JNZ TIM0_YEAR_DEC_END
            MOV TIM0_MINUTE, #59
            LJMP TIM0_YEAR_DEC_END
    TIM0_MINUTE_DEC_END:
    JNB TIM0_HOUR_CHOOSE, TIM0_HOUR_DEC_END
        DEC TIM0_HOUR
        MOV A, TIM0_HOUR
        CLR C
        SUBB A, #-1
        JNZ TIM0_YEAR_DEC_END
            MOV TIM0_HOUR, #23
            LJMP TIM0_YEAR_DEC_END
    TIM0_HOUR_DEC_END:
    JNB TIM0_DATE_CHOOSE, TIM0_DATE_DEC_END
        LCALL TIM0_DATE_TEST
        DEC TIM0_DATE
        MOV A, TIM0_DATE
        JNZ TIM0_YEAR_DEC_END
            MOV TIM0_DATE, TIM0_DATE_OVERFLOW
            DEC TIM0_DATE
            LJMP TIM0_YEAR_DEC_END
    TIM0_DATE_DEC_END:
    JNB TIM0_MONTH_CHOOSE, TIM0_MONTH_DEC_END
        DEC TIM0_MONTH
        MOV A, TIM0_MONTH
        JNZ MONTH_DEC_END
            MOV TIM0_MONTH, #12
        MONTH_DEC_END:
        LCALL TIM0_DATE_TEST
        MOV A, TIM0_DATE
        CLR C
        SUBB A, TIM0_DATE_OVERFLOW
        JC TIM0_YEAR_DEC_END
            MOV A, TIM0_DATE_OVERFLOW
            CLR C
            SUBB A, #1
            MOV TIM0_DATE, A
            LJMP TIM0_YEAR_DEC_END
    TIM0_MONTH_DEC_END:
    JNB TIM0_YEAR_CHOOSE, TIM0_YEAR_DEC_END
        DEC TIM0_YEAR
        LCALL TIM0_DATE_TEST
        MOV A, TIM0_DATE
        CLR C
        SUBB A, TIM0_DATE_OVERFLOW
        JC TIM0_YEAR_DEC_END
            MOV A, TIM0_DATE_OVERFLOW
            CLR C
            SUBB A, #1
            MOV TIM0_DATE, A
            LJMP TIM0_YEAR_DEC_END
    TIM0_YEAR_DEC_END:
    POP ACC
    RET

; ---------------TIM0---------------

; ---------------KEY---------------

; @brief 初始化按键 拉高 P10~P13 的 OD门 拉低 P17 的 OD 门
KEY_INIT:
    ORL P1, #00001111B
    ANL P1, #01111111B
    RET

; @brief 将扫描按键的结果放入 KEY 中
; @return KEY 扫描的按键 00H~0FH
; @return KEY_LONG 长按的按键 00H~0FH
KEY_SCAN:
    PUSH ACC
    PUSH B
    MOV A, P1
    ANL A, #00001111B
    MOV P1N_0, A
    CPL A
    ANL A, P1N_2
    MOV B, A
    MOV A, P1N_1
    CPL A
    ANL A, B
    CPL A
    ANL A, #00001111B
    MOV B, A
    CLR C
    SUBB A, KEY
    JZ KEY_SCAN_END
        MOV KEY, B
        MOV A, KEY
        CLR C
        SUBB A, #00001111B
        JZ KEY_SCAN_END
            MOV KEY_SCAN_TIME, TIM0_5ms
    KEY_SCAN_END:
    MOV A, KEY_LONG
    CLR C
    SUBB A, #00001111B
    JNZ KEY_LONG_DOWN_END
        MOV A, KEY_SCAN_TIME
        CLR C
        SUBB A, TIM0_5ms
        JNZ KEY_LONG_UP_END
            MOV B, KEY
            MOV A, P1
            CPL A
            ANL A, B
            JZ KEY_LONG_UP_END
                MOV KEY_LONG, P1N_2
        LJMP KEY_LONG_UP_END
    KEY_LONG_DOWN_END:
        MOV KEY_LONG, P1N_0
    KEY_LONG_UP_END:
    MOV P1N_2, P1N_1
    MOV P1N_1, P1N_0
    POP B
    POP ACC
    RET

; ---------------KEY---------------

; ---------------UART---------------

; @brief 串口初始化代码
UART_INIT:
    ORL P3, #03H
    MOV UART_BEG_PTR, #UART_DATA0
    MOV UART_END_PTR, #UART_DATA0
    MOV UART_DATA_SIZE, #0H
    ORL TMOD, #20H
    MOV TH1, #0FDH
    MOV TL1, #0FDH
    ANL PCON, #01111111B
    MOV SCON, #01010000B
    SETB TR1
    SETB EA
    SETB ES
    RET

; @brief 串口中断程序
UART_INTERRUPT:
    PUSH ACC
    SETB RS0
    JNB RI, UART_INTERRUPT_RECEIVE_END
        MOV A, UART_DATA_SIZE
        CLR C
        SUBB A, #16
        JZ UART_NOT_FULL_END
            INC UART_DATA_SIZE
            MOV R0, UART_END_PTR
            MOV @R0, SBUF
            INC UART_END_PTR
            MOV A, UART_END_PTR
            CJNE A, #68H, UART_END_PTR_LOOP_END
                MOV UART_END_PTR, #UART_DATA0
            UART_END_PTR_LOOP_END:
            UART_NOT_FULL_END:
            CLR RI
    UART_INTERRUPT_RECEIVE_END:
    JNB TI, UART_INTERRUPT_END
        CLR TI
    UART_INTERRUPT_END:
    CLR RS0
    POP ACC
    RETI

; ---------------UART---------------

; ---------------STOPWATCH---------------

; @brief 秒表初始化
STOPWATCH_INIT:
    MOV STOPWATCH_SECOND, #0
    MOV STOPWATCH_MINUTE, #0
    MOV STOPWATCH_HOUR, #0
    RET

; @brief 打开秒表
STOPWATCH_TURNON:
    MOV STOPWATCH_ON_5ms, TIM0_5ms
    SETB STOPWATCH_UPDATED
    SETB STOPWATCH_RUNNING
    RET

; @brief 更新内存中的秒表时间
STOPWATCH_UPDATE_TIME:
    PUSH ACC
    MOV A, TIM0_5ms
    CLR C
    SUBB A, STOPWATCH_ON_5ms
    JNZ STOPWATCH_UPDATE_END
        JB STOPWATCH_UPDATED, STOPWATCH_UPDATE_TIME_END
            SETB STOPWATCH_UPDATED
            INC STOPWATCH_SECOND
            MOV A, STOPWATCH_SECOND
            CJNE A, #60, STOPWATCH_UPDATE_TIME_END
                MOV STOPWATCH_SECOND, #0
                INC STOPWATCH_MINUTE
                MOV A, STOPWATCH_MINUTE
                CJNE A, #60, STOPWATCH_UPDATE_TIME_END
                    MOV STOPWATCH_MINUTE, #0
                    INC STOPWATCH_HOUR
    STOPWATCH_UPDATE_END:
        CLR STOPWATCH_UPDATED
    STOPWATCH_UPDATE_TIME_END:
    POP ACC
    RET


; ---------------STOPWATCH---------------

; ---------------TRANSCODE---------------

; @brief 将时间(分，时，秒)放到 LED 显示缓存中
; @param A 时间 秒 的地址(表格按 秒 分 时)存储
TRANSCODE_LEDBUF_TIME:
    PUSH ACC
    PUSH B
    SETB RS1
    MOV LED_SHOW_BUF_BLINKs, #00H
    MOV DPTR, #LED_TABLE
    MOV R0, #LED_SHOW_BUF0
    MOV R1, A
    MOV R7, #3
    TRANSCODE_LED_TIME_LOOP1:
        MOV R6, #2
        MOV A, @R1
        MOV R5, A
        TRANSCODE_LED_TIME_LOOP2:
            MOV A, R5
            MOV B, #10
            DIV AB
            MOV R5, A
            MOV A, B
            MOVC A, @A+DPTR
            MOV @R0, A
            INC R0
            DJNZ R6, TRANSCODE_LED_TIME_LOOP2
        DEC R7
        MOV A, R7
        JZ TRANSCODE_LED_TIME_LOOP_END
        MOV @R0, #01000000B
        INC R1
        INC R0
        SJMP TRANSCODE_LED_TIME_LOOP1
    TRANSCODE_LED_TIME_LOOP_END:
    JNB TIM0_SECOND_CHOOSE, TRANSCODE_SECOND_BLINK_END
        SETB LED_SHOW_BUF_BLINK0
        SETB LED_SHOW_BUF_BLINK1
    TRANSCODE_SECOND_BLINK_END:
    JNB TIM0_MINUTE_CHOOSE, TRANSCODE_MINUTE_BLINK_END
        SETB LED_SHOW_BUF_BLINK3
        SETB LED_SHOW_BUF_BLINK4
    TRANSCODE_MINUTE_BLINK_END:
    JNB TIM0_HOUR_CHOOSE, TRANSCODE_HOUR_BLINK_END
        SETB LED_SHOW_BUF_BLINK6
        SETB LED_SHOW_BUF_BLINK7
    TRANSCODE_HOUR_BLINK_END:
    CLR RS1
    POP B
    POP ACC
    RET

; @brief 将定时器时间(年、月、日)放到 LED 显示缓存中
TRANSCODE_LEDBUF_DATE:
    PUSH ACC
    PUSH B
    SETB RS1
    MOV LED_SHOW_BUF_BLINKs, #00H
    MOV DPTR, #LED_TABLE
    MOV R0, #LED_SHOW_BUF0
    MOV R1, #TIM0_DATE
    MOV R7, #3
    TRANSCODE_LED_DATE_LOOP1:
        MOV R6, #2
        MOV A, @R1
        MOV R5, A
        TRANSCODE_LED_DATE_LOOP2:
            MOV A, R5
            MOV B, #10
            DIV AB
            MOV R5, A
            MOV A, B
            MOVC A, @A+DPTR
            MOV @R0, A
            INC R0
            DJNZ R6, TRANSCODE_LED_DATE_LOOP2
        INC R1
        DJNZ R7, TRANSCODE_LED_DATE_LOOP1
    MOV A, TIM0_YEAR
    MOV B, #100
    DIV AB
    MOVC A, @A+DPTR
    MOV LED_SHOW_BUF6, A
    MOV LED_SHOW_BUF7, #01011011B ; 2
    MOV A, LED_SHOW_BUF2
    ORL A, #10000000B
    MOV LED_SHOW_BUF2, A
    MOV A, LED_SHOW_BUF4
    ORL A, #10000000B
    MOV LED_SHOW_BUF4, A
    JNB TIM0_DATE_CHOOSE, TRANSCODE_DATE_BLINK_END
        SETB LED_SHOW_BUF_BLINK0
        SETB LED_SHOW_BUF_BLINK1
    TRANSCODE_DATE_BLINK_END:
    JNB TIM0_MONTH_CHOOSE, TRANSCODE_MONTH_BLINK_END
        SETB LED_SHOW_BUF_BLINK2
        SETB LED_SHOW_BUF_BLINK3
    TRANSCODE_MONTH_BLINK_END:
    JNB TIM0_YEAR_CHOOSE, TRANSCODE_YEAR_BLINK_END
        SETB LED_SHOW_BUF_BLINK4
        SETB LED_SHOW_BUF_BLINK5
        SETB LED_SHOW_BUF_BLINK6
        SETB LED_SHOW_BUF_BLINK7
    TRANSCODE_YEAR_BLINK_END:
    CLR RS1
    POP B
    POP ACC
    RET

; @brief 将串口数据搬到TIM0时间缓存里
TRANSCODE_TIME_UART:
    PUSH ACC
    SETB RS1
    MOV A, UART_DATA_SIZE
    JZ TRANSCODE_TIME_UART_END
        MOV R0, UART_BEG_PTR
        MOV A, @R0
        CLR C
        SUBB A, #'t'
        JZ NOT_T_END
            MOV @R0, 0
            INC UART_BEG_PTR
            DEC UART_DATA_SIZE
            MOV A, UART_BEG_PTR
            CJNE A, #68H, TRANSCODE_TIME_UART_END
                MOV UART_BEG_PTR, #UART_DATA0
                SJMP TRANSCODE_TIME_UART_END
        NOT_T_END:
            MOV A, UART_DATA_SIZE
            CLR C
            SUBB A, #7
            JC TRANSCODE_TIME_UART_END
                DEC UART_DATA_SIZE
                MOV R1, #TIM0_SECOND
                MOV R7, #6
                TRANSCODE_TIME_UART_LOOP:
                    INC UART_BEG_PTR
                    DEC UART_DATA_SIZE
                    MOV R0, UART_BEG_PTR
                    CJNE R0, #68H, INC_SOLVE_END
                        MOV UART_BEG_PTR, #UART_DATA0
                        MOV R0, UART_BEG_PTR
                    INC_SOLVE_END:
                    MOV A, @R0
                    MOV @R1, A
                    INC R1
                    DJNZ R7, TRANSCODE_TIME_UART_LOOP
    TRANSCODE_TIME_UART_END:
    CLR RS1
    POP ACC
    RET

; ---------------TRANSCODE---------------

; ---------------MAIN---------------

MAIN:
    LCALL TIM0_DATE_INIT
    SETB SHOW_TIME_FLAG
    CLR SHOW_DATE_FLAG
    LCALL LED_INIT
    MOV P1, 0FFH
    LCALL KEY_INIT
    LCALL TIM0_INIT
    LCALL STOPWATCH_INIT
    LCALL UART_INIT

LOOP:
    LCALL TIM0_UPDATE_TIME
    LCALL TRANSCODE_TIME_UART

    JNB STOPWATCH_RUNNING, STOPWATCH_RUNNING_END
        LCALL STOPWATCH_UPDATE_TIME
    STOPWATCH_RUNNING_END:

    JNB SHOW_DATE_FLAG, SHOW_DATE_END
        LCALL TRANSCODE_LEDBUF_DATE
        SJMP SHOW_TIME_END
    SHOW_DATE_END:
        JNB SHOW_TIME_FLAG, SHOW_TIME_STATE_END
            MOV A, #TIM0_SECOND
        SHOW_TIME_STATE_END:

        JNB SHOW_STOPWATCH_FLAG, SHOW_STOPWATCH_STATE_END
            MOV A, #STOPWATCH_SECOND
        SHOW_STOPWATCH_STATE_END:

        JNB SHOW_ALARM_FLAG, SHOW_ALARM_STATE_END
            MOV A, #ALARM_SECOND
        SHOW_ALARM_STATE_END:

        LCALL TRANSCODE_LEDBUF_TIME
    SHOW_TIME_END:

    LCALL LED_SHOW_BUF

    ; 按键扫描 (每 0.1s 扫描一次, 连续扫描到 2次 认为按下)
    MOV A, TIM0_5ms
    MOV B, #10
    DIV AB
    MOV A, B
    CLR C
    SUBB A, #4
    JZ SCANING_TEST
        LJMP LOOP_END
        SCANING_TEST:
        MOV A, TIM0_5ms
        CLR C
        SUBB A, KEY_TIME
        JNZ SCANING_TEST_END
            LJMP LOOP_END
            SCANING_TEST_END:
            LCALL KEY_SCAN

            JB KEY0, KEY0_END

                ; 从修改状态返回显示状态
                JNB TIME_CHANGE_FLAG, TIME_CHANGE_RETURN_END
                    CLR TIME_CHANGE_FLAG
                    MOV TIM0_CHOOSE_FLAGs, #00H
                    SJMP KEY0_END
                TIME_CHANGE_RETURN_END:

                ; 秒表状态返回键
                JNB SHOW_STOPWATCH_FLAG, SHOW_STOPWATCH_FLAG_END
                    JB STOPWATCH_RUNNING, STOPWATCH_INIT_END
                        MOV A, STOPWATCH_SECOND
                        ORL A, STOPWATCH_MINUTE
                        ORL A, STOPWATCH_HOUR
                        JZ STOPWATCH_INIT_END
                            LCALL STOPWATCH_INIT
                            SJMP KEY0_END
                    STOPWATCH_INIT_END:
                    CLR SHOW_STOPWATCH_FLAG
                    SETB SHOW_TIME_FLAG
                    SJMP KEY0_END
                SHOW_STOPWATCH_FLAG_END:

                ; 闹钟状态返回键
                JNB SHOW_ALARM_FLAG, SHOW_ALARM_FLAG_END
                    CLR SHOW_ALARM_FLAG
                    SETB SHOW_TIME_FLAG
                    SJMP KEY0_END
                SHOW_ALARM_FLAG_END:

                ; 更改显示状态--时钟或日期 放在最后
                CPL SHOW_TIME_FLAG
                CPL SHOW_DATE_FLAG

            KEY0_END:

            JB KEY1, KEY1_END

                ; 时间修改键(减少)
                JNB TIME_CHANGE_FLAG, TIME_CHANGE_DEC_END
                    LCALL TIM0_DEC_CHOOSE
                    SJMP KEY1_END
                TIME_CHANGE_DEC_END:

                ; 显示秒表键 放在最后
                JB SHOW_STOPWATCH_FLAG, KEY1_END
                    CLR SHOW_TIME_FLAG
                    CLR SHOW_DATE_FLAG
                    SETB SHOW_STOPWATCH_FLAG

            KEY1_END:

            JB KEY_LONG1, KEY_LONG1_END
                JNB TIME_CHANGE_FLAG, KEY_LONG1_END
                    LCALL TIM0_DEC_CHOOSE
            KEY_LONG1_END:

            JB KEY2, KEY2_END

                ; 秒表防重键
                JB SHOW_STOPWATCH_FLAG, KEY2_END

                ; 时间修改键(增加)
                JNB TIME_CHANGE_FLAG, TIME_CHANGE_INC_END
                    LCALL TIM0_INC_CHOOSE
                    SJMP KEY2_END
                TIME_CHANGE_INC_END:

                ; 显示闹钟键 放在最后
                JB SHOW_ALARM_FLAG, KEY2_END
                    SETB SHOW_ALARM_FLAG

            KEY2_END:

            JB KEY_LONG2, KEY_LONG2_END
                JNB TIME_CHANGE_FLAG, KEY_LONG2_END
                    LCALL TIM0_INC_CHOOSE
            KEY_LONG2_END:

            JB KEY3, KEY3_END

                ; 秒表开始/停止计时按键
                JNB SHOW_STOPWATCH_FLAG, STOPWATCH_TURN_END
                    JB STOPWATCH_RUNNING, STOPWATCH_TURNON_END
                        LCALL STOPWATCH_TURNON
                        SJMP KEY3_END
                    STOPWATCH_TURNON_END:
                        CLR STOPWATCH_RUNNING
                        SJMP KEY3_END
                STOPWATCH_TURN_END:

                ; 进入时间修改 放在最后
                JB TIME_CHANGE_FLAG, TIME_CHANGE_SET
                    SETB TIME_CHANGE_FLAG
                    JNB SHOW_TIME_FLAG, TIM0_SECOND_CHOOSE_END
                        SETB TIM0_SECOND_CHOOSE
                        LJMP KEY3_END
                    TIM0_SECOND_CHOOSE_END:
                        SETB TIM0_DATE_CHOOSE
                        LJMP KEY3_END
                TIME_CHANGE_SET:
                    ANL TIM0_CHOOSE_FLAGs, #00111111B
                    MOV A, TIM0_CHOOSE_FLAGs
                    ANL A, #00100100B
                    JNZ TIM0_CHOOSE_RIGHT_END
                        MOV A, TIM0_CHOOSE_FLAGs
                        RL A
                        SJMP TIM0_CHOOSE_CANNOT_RIGHT_END
                    TIM0_CHOOSE_RIGHT_END:
                        MOV A, TIM0_CHOOSE_FLAGs
                        RR A
                        RR A
                    TIM0_CHOOSE_CANNOT_RIGHT_END:
                    MOV TIM0_CHOOSE_FLAGs, A
            KEY3_END:

            MOV KEY_TIME, TIM0_5ms

    LOOP_END:
    LJMP LOOP

; ---------------MAIN---------------

END
